package com.rd.emf.geneditor.control.handler;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.emf.common.ui.URIEditorInput;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl;
import org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.xsd.ecore.XSDEcoreBuilder;

import com.rd.emf.geneditor.view.dialogs.InstanceCreatorDialog;
import com.rd.emf.geneditor.view.editors.generic.EMFGenericEditor;
import com.rd.xsd.common.CommonPackage;

@SuppressWarnings("restriction")
public class OpenSchemaHandler extends AbstractHandler {

	public static final String OPEN_TEST_COMMAND_ID = "genericeditor.LoadSchemaMenu";
	private static final String PACKAGE_EXPLORER_ID = "org.eclipse.jdt.ui.PackageExplorer";

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {

		Shell shell = HandlerUtil.getActiveShellChecked(event);

		FileDialog fileDialog = new FileDialog(shell, SWT.OPEN);
		String[] args = { "*.XSD" };
		fileDialog.setFilterExtensions(args);
		fileDialog.setText("Open File");
		String path = fileDialog.open();

		if (path != null && path.length() > 0) {

			// File file = new File(path);
			XSDEcoreBuilder xsdEcoreBuilder = new XSDEcoreBuilder();
			xsdEcoreBuilder.getTargetNamespaceToEPackageMap().put(CommonPackage.eNS_URI, CommonPackage.eINSTANCE);
			Collection<EObject> eCorePackages = xsdEcoreBuilder.generate(URI.createFileURI(path));

			if (eCorePackages.size() > 0) {
				try {
					// Register model in package registry
					for (EObject eObject : eCorePackages) {
						EPackage ePackage = (EPackage) eObject;
						Object previous = EPackage.Registry.INSTANCE.put(ePackage.getNsURI(), ePackage);
						if (previous != null) {
							System.out.println("Previous model with the same URI  --> " + previous.toString());
						}
					}

					// get available complex types (EStructuralFeatures) names for dialog
					Map<EPackage, EStructuralFeature> availableFeatures = new HashMap<EPackage, EStructuralFeature>();
					for (EObject eObject : eCorePackages) {
						if (eObject instanceof EPackage) {
							EPackage ePackage = (EPackage) eObject;
							EClass rootEClass = ExtendedMetaData.INSTANCE.getDocumentRoot(ePackage);
							if (rootEClass != null) {
								List<EStructuralFeature> allElements = ExtendedMetaData.INSTANCE
										.getAllElements(rootEClass);
								for (EStructuralFeature eStructuralFeature : allElements) {
									if (eStructuralFeature.isChangeable()) {
										EClassifier eClassifier = eStructuralFeature.getEType();
										if (eClassifier instanceof EClass) {
											EClass eClass = (EClass) eClassifier;
											if (!eClass.isAbstract()) {
												availableFeatures.put(ePackage, eStructuralFeature);
											}
										}
									}
								}
							}
						}
					}

					Map.Entry<EPackage, EStructuralFeature> featureToCreate = null;

					if (availableFeatures.size() > 0) {
						if (availableFeatures.size() == 1) {
							featureToCreate = availableFeatures.entrySet().iterator().next();
						} else {
							// opens dialog, so that the user can chose what element to pick
							InstanceCreatorDialog icDialog = new InstanceCreatorDialog(HandlerUtil
									.getActiveShellChecked(event), availableFeatures);
							if (icDialog.open() == Window.OK) {
								featureToCreate = icDialog.getSelectedItem();
							}
						}

						if (featureToCreate != null) {
							EPackage selectedEPackage = featureToCreate.getKey();
							EStructuralFeature selectedEStructuralFeature = featureToCreate.getValue();
							// creates the new EObject
							EClass eClass = ExtendedMetaData.INSTANCE.getDocumentRoot(selectedEPackage);
							EObject rootObject = selectedEPackage.getEFactoryInstance().create(eClass);
							rootObject.eSet(selectedEStructuralFeature, EcoreUtil
									.create((EClass) selectedEStructuralFeature.getEType()));

							// creates a resource set
							ResourceSet resourceSet = new ResourceSetImpl();
							resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("emp",
									new XMLResourceFactoryImpl());

							// get current open project name and builds a platform resource URI
							Object selected = ((IStructuredSelection) PlatformUI.getWorkbench()
									.getActiveWorkbenchWindow().getActivePage().getSelection()).getFirstElement();

							IProject project = null;
							if (selected instanceof IProject) {
								project = (IProject) selected;
							} else if (selected instanceof IResource) {
								IResource resource = (IResource) selected;
								project = resource.getProject();
							}

							if (project != null) {
								IPath filePath = project.getFullPath().append(
										selectedEStructuralFeature.getName().concat(".emp"));
								URI fileURI = URI.createPlatformResourceURI(filePath.toString(), true);

								// stores data to file
								Resource resource = resourceSet.createResource(fileURI);
								resource.getContents().add(rootObject);
								try {
									resource.save(Collections.EMPTY_MAP);
									IViewPart viewPart = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
											.getActivePage().findView(PACKAGE_EXPLORER_ID);
									if (viewPart instanceof PackageExplorerPart) {
										PackageExplorerPart packageExplorer = (PackageExplorerPart) viewPart;
										packageExplorer.refresh(new StructuredSelection(resource));
									}
								} catch (IOException e) {
									e.printStackTrace();
								}

								// prepare editor input and open editor
								IEditorInput ei = new URIEditorInput(fileURI, fileURI.lastSegment());
								IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
										.getActivePage();
								try {
									page.openEditor(ei, EMFGenericEditor.EDITOR_ID, true, IWorkbenchPage.MATCH_INPUT);
								} catch (PartInitException e) {
									e.printStackTrace();
								}
							}
						}
					} else {
						MessageDialog.openWarning(shell, "No features available",
								"Could not find any features to create the model");
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		return null;
	}
}
